#include "../include/head.h"

int epolladd(int epfd,int fd){
    struct epoll_event event;
    event.events=EPOLLIN;
    event.data.fd=fd;
    epoll_ctl(epfd,EPOLL_CTL_ADD,fd,&event);
    return 0;
}

int epolldel(int epfd,int fd){
    epoll_ctl(epfd,EPOLL_CTL_DEL,fd,NULL);
    return 0;
}
int CalMD5(char* filepath, char* md5)
{
    printf("计算MD5中\n");
    MD5_CTX ctx;
    MD5_Init(&ctx);
    int openfd = open(filepath,O_RDWR);

    if(openfd==-1)
    {
        printf("file_path = %s\n", filepath);
        return -1;
    }
    char buf[4096];
    unsigned char md[16];
    while(1)
    {
        bzero(buf,4096);
        ssize_t sret = read(openfd,buf,sizeof(buf));
        if(sret == 0)
        {
            break;
        }
        MD5_Update(&ctx,buf,sret);
    }
    MD5_Final(md,&ctx);
    for(int i=0;i<16;++i)
    {
        char temp[3]={0};
        sprintf(temp,"%02x",md[i]);
        strcat(md5,temp);
    }
    close(openfd);
    return 0;
}
int salt_create(char* desc){
    char salt_array[64]={
        'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
        'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
        'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
        'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
        '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '.', '/'
    };

    srand(time(NULL));
    char arr[21]={0};
    for(int i=0;i<16;i++){
        int x=rand()%64;
        arr[i]=salt_array[x];
    }
    printf("随机生成%s\n",arr);

    char pre[]="$6$";
    char suf[]="$";
    snprintf(desc,30,"%s%s%s",pre,arr,suf);
    int n=strlen(desc);
    printf("%s的长度为%d\n",desc,n);

    return 0;
    //
}

// 带安全限制的版本 的字符串截取
int getstr(const char *src, int n, char *dest, size_t dest_size) {
    char *workbuf = strdup(src); // 创建可修改副本
    if(!workbuf) return -1;

    char *token = strtok(workbuf, " ");
    int count = 1;
    int result = -1;

    while(token) {
        if(count == n) {
            strncpy(dest, token, dest_size-1);
            dest[dest_size-1] = '\0';
            result = 0;
            break;
        }
        token = strtok(NULL, " ");
        count++;
    }

    free(workbuf);
    return result;
}

//判断用户输入的参数个数是否合规
int checkout_num(const char *buf){
    char tmp[4096]={0};
    memcpy(tmp,buf,strlen(buf));
    char *p=strtok(tmp," ");
    int real=1;
    while(p!=NULL){
        p=strtok(NULL," ");
        real++;
    }
    --real; //去掉加NULL多加的一次
    return  real;
}

//初步判断用户输入
int simplejudge(char* readbuf,int* target,char *now_path_buf)
{
    int ret=checkout_num(readbuf);
    if(ret>3){
        printf("用户输入的格式有错误，请重新输入!\n");
        return -1;
    }

    char buf[1024]={0};
    getstr(readbuf,1,buf,1024);
    printf("用户命令：%s\n",buf);

    if(strcmp(buf,"cd")==0)
    {
        if (checkout_num(readbuf) != 2)
        {
            printf("用户输入的格式有错误，请重新输入!\n");
            return -1;
        }
        *target=C_OP_CD;
    }
    else if(strcmp(buf,"ls")==0)
    {
        if(checkout_num(readbuf)!=1){
            printf("用户输入的格式有错误，请重新输入!\n");
            return -1;
        }
        *target=C_OP_LS;
    }
    else if(strcmp(buf,"pwd")==0)
    {
        if(checkout_num(readbuf)!=1){
            printf("用户输入的格式有错误，请重新输入!\n");
            return -1;
        }
        printf("%s\n", now_path_buf);
        return -1;
    }
    else if (strcmp(buf, "rmdir") == 0)
    {
        if(checkout_num(readbuf)!=2){
            printf("用户输入的格式有错误，请重新输入!\n");
            return -1;
        }
        *target=C_OP_RMDIR;
    }
    else if (strcmp(buf, "mkdir") == 0)
    {

        if(checkout_num(readbuf)!=2){
            printf("用户输入的格式有错误，请重新输入!\n");
            return -1;
        }
        *target=C_OP_MKDIR;
    }
    else if (strcmp(buf, "remove") == 0)
    {

        if(checkout_num(readbuf)!=2){
            printf("用户输入的格式有错误，请重新输入!\n");
            return -1;
        }
        *target=C_OP_REMOVE;
    }
    else if(strcmp(buf,"gets")==0){

        if(checkout_num(readbuf)!=3){
            printf("用户输入的格式有错误，请重新输入!\n");
            return -1;
        }
        char p[10]={0}; 
        getstr(readbuf,3,p,10);
        if(opendir(p)==NULL){
            printf("此路径不存在!\n");
            return -1;
        }
        *target=C_OP_GETS_QUERY;

    }
     else if(strcmp(buf,"puts")==0){
         if(checkout_num(readbuf)!=3){
             printf("用户输入的格式有错误，请重新输入!\n");
             return -1;
         }
         char p[64]={0};
         printf("%s\n", readbuf);
         getstr(readbuf, 2, p, 64);
         printf("%s\n", p);
         if (access(p, F_OK) == -1)
         {
             printf("上传的文件不存在!\n");
             return -1;
         }

        *target=C_OP_PUTS_QUERY;
    }
    else
    {
        printf("buf_len = %ld\n", strlen(buf));
        printf("用户输入的命令有错误，请重新输入!\n");
        return -1;
    }
    return 0;
}



int submit(int netfd,char* buf,int target)
{   //封装包，上传
    RequestPackage* train=(RequestPackage *)calloc(1,sizeof(RequestPackage));
    //char vir_path[1024]={0};
    char tmp[1024]={0};
    char tmpp[1024]={0};
    char tmpbuf[3072]={0};
    switch (target)
    {
    case C_OP_LS:
        train->type=C_OP_LS;
        send(netfd,&train->type,sizeof(int),MSG_NOSIGNAL);
        train->args_len=0;
        send(netfd,&train->args_len,sizeof(train->args_len),MSG_NOSIGNAL);
        break;
    case C_OP_CD:
        // 发T
        train->type=C_OP_CD;
        send(netfd,&train->type,sizeof(int),MSG_NOSIGNAL);

        // 发args
        bzero(tmp,sizeof(tmp));
        getstr(buf,2,tmp,1024);
        train->args_len=strlen(tmp);
        send(netfd,&train->args_len,sizeof(int),MSG_NOSIGNAL);
        memcpy(train->args_val,tmp,strlen(tmp));
        send(netfd,train->args_val,train->args_len,MSG_NOSIGNAL);
        break;
    case C_OP_RMDIR:
        train->type=C_OP_RMDIR;
        send(netfd,&train->type,sizeof(int),MSG_NOSIGNAL);

        // 发args
        bzero(tmp,sizeof(tmp));
        getstr(buf,2,tmp,1024);
        train->args_len=strlen(tmp);
        send(netfd,&train->args_len,sizeof(int),MSG_NOSIGNAL);
        memcpy(train->args_val,tmp,strlen(tmp));
        send(netfd,train->args_val,train->args_len,MSG_NOSIGNAL);

        break;
    case C_OP_MKDIR:
        train->type=C_OP_MKDIR;
        send(netfd,&train->type,sizeof(int),MSG_NOSIGNAL);

        // 发args
        bzero(tmp,sizeof(tmp));
        getstr(buf,2,tmp,1024);
        train->args_len=strlen(tmp);
        send(netfd,&train->args_len,sizeof(int),MSG_NOSIGNAL);
        memcpy(train->args_val,tmp,strlen(tmp));
        send(netfd,train->args_val,train->args_len,MSG_NOSIGNAL);
        break;

    case C_OP_REMOVE:
        train->type=C_OP_REMOVE;
        send(netfd,&train->type,sizeof(int),MSG_NOSIGNAL);

        // // 发vir_path_len
        // bzero(vir_path,sizeof(vir_path));
        // ClientVirtualPathStack_print(p,vir_path);
        // train->vir_path_len=strlen(vir_path);
        // memcpy(train->vir_path_val,vir_path,train->vir_path_len);
        // send(netfd,&train->vir_path_len,sizeof(int),MSG_NOSIGNAL);
        // send(netfd,train->vir_path_val,train->vir_path_len,MSG_NOSIGNAL);

        // 发args
        bzero(tmp,sizeof(tmp));
        getstr(buf,2,tmp,1024);
        train->args_len=strlen(tmp);
        send(netfd,&train->args_len,sizeof(int),MSG_NOSIGNAL);
        memcpy(train->args_val,tmp,strlen(tmp));
        send(netfd,train->args_val,train->args_len,MSG_NOSIGNAL);
        break;
    case C_OP_PUTS_QUERY:
        {
            train->type=C_OP_PUTS_QUERY;
            printf("bufff = %s\n", buf);

            // 发args
            bzero(tmp,sizeof(tmp));
            getstr(buf,2,tmp,1024); 
            bzero(tmpp,sizeof(tmpp));
            getstr(buf,3,tmpp,1024);
            char md5[33]={0};
            if(CalMD5(tmp,md5)==-1)
            {
                printf("计算md5失败！\n");
                return -1;
            };

            bzero(tmpbuf,sizeof(tmpbuf));
            snprintf(tmpbuf, sizeof(tmpbuf), "%s %s %s", tmp,tmpp,md5);
            printf("puts args:%s\n",tmpbuf); 
            train->args_len=strlen(tmpbuf);
            memcpy(train->args_val,tmpbuf,train->args_len);
            send(netfd, &train->type, sizeof(int), MSG_NOSIGNAL);
            send(netfd, &train->args_len, sizeof(int), MSG_NOSIGNAL);
            send(netfd,train->args_val,train->args_len,MSG_NOSIGNAL);
            break;
        }
    case C_OP_GETS_QUERY:
        { 
            train->type=C_OP_GETS_QUERY;
            send(netfd,&train->type,sizeof(int),MSG_NOSIGNAL);


            // 发args
            bzero(tmp,sizeof(tmp));
            getstr(buf,2,tmp,1024); 
            bzero(tmpp,sizeof(tmpp));
            getstr(buf,3,tmpp,1024);

            bzero(tmpbuf,sizeof(tmpbuf));
            snprintf(tmpbuf, sizeof(tmpbuf), "%s %s", tmp,tmpp);
            DIR *dir = opendir(tmpp);
            if (dir == NULL) {
                printf("非法路径：%s\n",tmpp);
                //closedir(dir);
                return -1;
            }
            closedir(dir);
            train->args_len=strlen(tmpbuf);
            memcpy(train->args_val,tmpbuf,train->args_len);
            send(netfd,&train->args_len,sizeof(int),MSG_NOSIGNAL);
            send(netfd,train->args_val,train->args_len,MSG_NOSIGNAL);

            break;
        }
    }
    return 0;
}


int recv_resolver(int target,int args_len,char*args,char*now_path_buf,int sockfd)
{

    printf("client res type:%d\n", target);
    switch (target)
    {
    case CD_SUCCESS:
        client_cd(target,args_len,args,sockfd,now_path_buf);
        break;

    case  LS_SUCCESS:
        client_ls(target,args_len,args,sockfd,now_path_buf);
        break;

        // case RES_GETS:
        // client_gets(presponse,pvirtualpathstack,socked_fd);
        //     break;

        // // case RES_PUTS:
        // //     client_puts(presponse,pvirtualpathstack,socked_fd);
        //     break;
    case RES_PUTS_COMFIRM:
        client_puts_comfirm(target,args_len,args,sockfd,now_path_buf);
        break;

    case RES_GETS_COMFIRM:
        client_gets_comfirm(target,args_len,args,sockfd,now_path_buf);
        break;

    case RMDIR_SUCCESS:
        client_rmdir(target,args_len,args,sockfd,now_path_buf);
        break;
    case MKDIR_SUCCESS:
        client_mkdir(target,args_len,args,sockfd,now_path_buf);
        break;
    case REMOVE_SUCCESS:
        client_rmfile(target,args_len,args,sockfd,now_path_buf);    
        break;
    case DIR_ERR: 
        printf("%s\n", args);    
        // default:
        //     printf("接收错误\n");
        break;
    }
    return 0;
}



int main(int argc, char *argv[])
{

    char now_path_buf[512] = {0};

    //连接socket
    int sockfd=socket(AF_INET,SOCK_STREAM,0);
    struct sockaddr_in addr;
    bzero(&addr,sizeof(addr));
    addr.sin_family=AF_INET;
    addr.sin_addr.s_addr=inet_addr("127.0.0.1");
    addr.sin_port=htons(30000);
    int ret=connect(sockfd,(struct sockaddr*)&addr,sizeof(addr));
    ERROR_CHECK(ret,-1,"connect");

    //epfd初始化
    int epfd=epoll_create(1);
    epolladd(epfd,STDIN_FILENO);
    epolladd(epfd,sockfd);

    //缓冲区
    char readbuf[4096]={0}; //接收stdin数据

    //客户端是否退出标志
    int is_alive=1; //1活 0死

    struct epoll_event readySet[1024]={0};

    ResponsePackage* response=(ResponsePackage*)calloc(1,sizeof(ResponsePackage));
    char user_name_buf[256]={0};
    char user_password_buf[256]={0};
    char args_buf[1024]={0};

    while (1)
    {
        memset(response, 0, sizeof(ResponsePackage));

        bzero(user_name_buf, sizeof(user_name_buf));
        bzero(user_password_buf, sizeof(user_password_buf));

        int tag;
        printf("请选择 1.登录 2.注册\n");
        scanf("%d", &tag);
        if(tag == 1)
        {
            response->type=USER_LOGIN;
            printf("请输入用户名：\n");
            scanf("%s", user_name_buf);

            // printf("用户名为：%s\n", user_name_buf);
            printf("正在检测用户名是否存在...\n");

            response->args_len = strlen(user_name_buf);
            memcpy(response->args_val, user_name_buf, response->args_len);
            send(sockfd, &response->type, sizeof(int), MSG_NOSIGNAL);
            send(sockfd, &response->args_len, sizeof(int), MSG_NOSIGNAL);
            send(sockfd, response->args_val, response->args_len, MSG_NOSIGNAL);

            memset(response, 0, sizeof(ResponsePackage));

            int ret = recvn(sockfd, &response->type, sizeof(int), NULL);
            if(ret == -1)
            {
                printf("服务端已断开链接！\n");
                is_alive = 0;
                break;
            }
            ret = recvn(sockfd, &response->args_len, sizeof(int), NULL);
            if(ret == -1)
            {
                printf("服务端已断开链接！\n");
                is_alive = 0;
                break;
            }
            if(response->args_len != 0)
            {
                ret = recvn(sockfd, response->args_val, response->args_len, NULL);
                if(ret == -1)
                {
                    printf("服务端已断开链接！\n");
                    is_alive = 0;
                    break;
                }
            }


            if(response->type == L_R_SUCCESS)
            {
                printf("用户名检查成功！\n");
            }
            else if(response->type == L_R_ERR)
            {
                printf("登录失败,请重新登录!,失败原因: %s\n", response->args_val);
                continue;
            }

            char setting[30] = {0};
            memcpy(setting, response->args_val, response->args_len);
            // printf("%s\n", setting);

            printf("请输入密码：\n");
            scanf("%s", user_password_buf);

            // 通过返回的盐值计算密码密文
            char *ciphertest = crypt(user_password_buf, setting);

            sprintf(args_buf, "%s %s", user_name_buf,ciphertest);

            memset(response, 0, sizeof(ResponsePackage));

            // 发送用户名和密码密文
            response->type=USER_LOGIN2;
            response->args_len = strlen(args_buf);
            memcpy(response->args_val, args_buf, response->args_len);
            // printf("%s\n", response->args_val);

            send(sockfd, &response->type, sizeof(int), MSG_NOSIGNAL);
            send(sockfd, &response->args_len, sizeof(int), MSG_NOSIGNAL);
            send(sockfd, response->args_val, response->args_len, MSG_NOSIGNAL);

            // 接受服务端对于密码的验证
            memset(response, 0, sizeof(ResponsePackage));

            ret = recvn(sockfd, &response->type, sizeof(int), NULL);
            if(ret == -1)
            {
                printf("服务端已断开链接！\n");
                is_alive = 0;
                break;
            }
            ret = recvn(sockfd, &response->args_len, sizeof(int), NULL);
            if(ret == -1)
            {
                printf("服务端已断开链接！\n");
                is_alive = 0;
                break;
            }
            if(response->args_len != 0)
            {
                ret = recvn(sockfd, response->args_val, response->args_len, NULL);
                if(ret == -1)
                {
                    printf("服务端已断开链接！\n");
                    is_alive = 0;
                    break;
                }
            }
            if(response->type == L_R_SUCCESS)
            {
                printf("登录成功！MyGO!!!!!\n");
                break;
            }
            else if(response->type == L_R_ERR)
            {
                printf("登录失败,请重新登录!,失败原因: %s\n", response->args_val);
                continue;
            }

        }
        else if(tag == 2)
        {
            response->type=USER_REGI;

            printf("请输入用户名：\n");
            scanf("%s", user_name_buf);
            printf("请输入密码：\n");
            scanf("%s", user_password_buf);

            // 生成一个随机盐值
            char setting[30] = {0};
            salt_create(setting);
            char *ciphertest = crypt(user_password_buf, setting);

            // 将用户名、盐值、密文密码拼接
            sprintf(args_buf, "%s %s %s", user_name_buf, setting,ciphertest);
            // printf("拼接后：%s\n", args_buf);

            memcpy(response->args_val, args_buf, strlen(args_buf));


            send(sockfd, &response->type, sizeof(int), MSG_NOSIGNAL);
            response->args_len = strlen(response->args_val);
            // printf("发送的用户名+盐值+密文密码的总长度为：%d\n", response->args_len);
            send(sockfd, &response->args_len, sizeof(int), MSG_NOSIGNAL);
            send(sockfd, response->args_val, response->args_len, MSG_NOSIGNAL);

            memset(response, 0, sizeof(ResponsePackage));

            printf("等待服务端检查...\n");
            // 接受服务端对此次登录/注册请求的检查
            int ret = recvn(sockfd, &response->type, sizeof(int), NULL);
            if(ret == -1)
            {
                printf("服务端已断开链接！\n");
                is_alive = 0;
                break;
            }
            ret = recvn(sockfd, &response->args_len, sizeof(int), NULL);
            if(ret == -1)
            {
                printf("服务端已断开链接！\n");
                is_alive = 0;
                break;
            }
            if(response->args_len!=0)
            {
                ret = recvn(sockfd, response->args_val, response->args_len, NULL);
                if(ret == -1)
                {
                    printf("服务端已断开链接！\n");
                    is_alive = 0;
                    break;
                }
            }

            // 检查返回的标志位
            if(response->type == L_R_SUCCESS)
            {
                printf("注册成功,MyGO!!!!!\n");
                break;
            }
            else if(response->type == L_R_ERR)
            {
                printf("登录失败,请重新登录!,失败原因: %s\n", response->args_val);
                continue;
            }
        }





    }

    while(is_alive){
        int num=epoll_wait(epfd,readySet,1024,-1);
        for(int i=0;i<num;i++){
            if(readySet[i].data.fd==STDIN_FILENO)
            {

                bzero(readbuf,sizeof(readbuf));
                int submittype=-100;
                ssize_t sret=read(STDIN_FILENO,readbuf,sizeof(readbuf));
                if(sret == 0){
                    //客户端退出指令
                    is_alive=0;
                    break;
                }else{

                    //去掉接收到的末尾\n换行符
                    readbuf[strlen(readbuf)-1]='\0';  

                    // 判断用户输入指令是否正确 正确封包 错误等待用户重新输入
                    if(simplejudge(readbuf,&submittype,now_path_buf)==0){
                        submit(sockfd,readbuf,submittype);
                    }
                }

            }
            else if(readySet[i].data.fd==sockfd)
            {
                memset(response, 0, sizeof(ResponsePackage));

                // 对服务端传入的包进行解析
                int ret = recvn(sockfd, &response->type, sizeof(int), NULL);
                if(ret == -1)
                {
                    printf("服务端已断开链接！\n");
                    is_alive = 0;
                    break;
                }

                ret = recvn(sockfd, &response->args_len, sizeof(int), NULL);
                if(ret == -1)
                {
                    printf("服务端已断开链接！\n");
                    is_alive = 0;
                    break;
                }
                if(response->args_len !=0)
                {
                    ret = recvn(sockfd, &response->args_val, response->args_len, NULL);
                    if(ret == -1)
                    {
                        printf("服务端已断开链接！\n");
                        is_alive = 0;
                        break;
                    }
                }
                printf("已接收%d\n",response->type);
                recv_resolver(response->type,response->args_len,response->args_val,now_path_buf,sockfd);
            }

        }
    }
    close(sockfd);
    return 0;
}

